<template>
    <div class="create-edit-modal-wrapper">
        <el-dialog :model-value="props.value" :title="dialog.title" :width="dialog.width" destroy-on-close>
            <el-form ref="ruleFormRef" :model="formData" :rules="ruleForm" label-width="110px">
                <el-form-item label="协议名称" prop="protocolName">
                    <el-input
                        placeholder="请输入协议名称"
                        v-model="formData.protocolName"
                        @input="value => (formData.protocolName = value.trim())"
                        maxlength="50"
                    />
                </el-form-item>
                <el-form-item label="标识符" prop="protocolNo">
                    <el-input
                        placeholder="请输入标识符"
                        v-model="formData.protocolNo"
                        @input="value => (formData.protocolNo = value.trim())"
                        :disabled="isEdit()"
                        maxlength="32"
                    />
                </el-form-item>
                <el-form-item label="协议类型" prop="protocolType">
                    <el-select
                        placeholder="请选择协议类型"
                        :disabled="isEdit()"
                        @change="handleProtocolTypeChange"
                        v-model="formData.protocolType"
                    >
                        <el-option
                            v-for="(item, i) in protocolTypeList"
                            :label="item.protocolType"
                            :key="i"
                            :value="item.protocolType"
                            :disabled="item.protocolType === 'tcp'"
                        />
                    </el-select>
                </el-form-item>
                <el-form-item label="是否启用脚本" required>
                    <el-radio-group
                        v-model="formData.enableScript"
                        @change="handleEnableScriptChange"
                        :disabled="isEdit()"
                    >
                        <el-radio :value="true">是</el-radio>
                        <el-radio :value="false">否</el-radio>
                    </el-radio-group>
                </el-form-item>
                <el-form-item label="脚本" v-if="formData.enableScript" prop="scriptNo">
                    <el-select
                        :placeholder="formData.protocolType ? '请选择脚本' : '选择协议类型后选择'"
                        v-model="formData.scriptNo"
                        :disabled="!formData.protocolType"
                    >
                        <el-option
                            v-for="(item, i) in scriptMapList[formData.protocolType]"
                            :label="item.scriptName"
                            :key="i"
                            :value="item.scriptNo"
                        />
                    </el-select>
                </el-form-item>
                <el-form-item label="校验方式" v-else>
                    <el-select
                        placeholder="请选择校验方式"
                        v-model="formData.checkType"
                        @change="handleCheckTypeChange"
                        clearable
                    >
                        <el-option v-for="(value, key) in CheckType" :label="value" :key="key" :value="key" />
                    </el-select>
                </el-form-item>
                <template v-if="formData.checkType === 'crc'">
                    <el-form-item label="CRC类型" prop="crcType">
                        <el-select placeholder="请选择CRC类型" v-model="formData.crcType" @change="handleCrcTypeChange">
                            <el-option v-for="(value, key) in CrcType" :label="value" :key="key" :value="key" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="CRC名称" prop="checkName" required>
                        <el-select placeholder="请选择CRC名称" v-model="formData.checkName" @change="handleCrcChange">
                            <el-option
                                v-for="(item, i) in crcMapList[formData.crcType]"
                                :label="item.crcName"
                                :key="i"
                                :value="item.crcName"
                            />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="CRC初始值" required>
                        <el-input disabled v-model="formData.crcInitValue" />
                    </el-form-item>
                    <el-form-item label="CRC表达式" required>
                        <el-input disabled v-model="formData.crcMultinomial" />
                    </el-form-item>
                </template>
                <template v-else-if="formData.checkType === 'hash'">
                    <el-form-item label="哈希名称" prop="checkName" required>
                        <el-select placeholder="请选择哈希名称" v-model="formData.checkName">
                            <el-option v-for="(value, key) in HashType" :label="value" :key="key" :value="key" />
                        </el-select>
                    </el-form-item>
                </template>
                <el-form-item label="描述" style="width: 100%; margin-left: 0">
                    <el-input
                        v-model="formData.protocolDescription"
                        type="textarea"
                        maxlength="200"
                        show-word-limit
                        placeholder="请输入描述"
                    />
                </el-form-item>
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button @click="props.close">取消</el-button>
                    <el-button type="primary" @click="submitForm" :loading="loading">确定</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus';
import { IoTProtocolService, runScriptService } from '@great/services';
import { reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import type { PopupBoxProps } from '@great/utils';
import { useRequest } from 'vue-request';
import { HashType, CrcType, CheckType } from '@/utils/constant';

interface IProps extends PopupBoxProps {
    row?: Record<string, any>;
    callBack?: () => Promise<void>;
}
const props = defineProps<IProps>();
const router = useRouter();

interface Dialog {
    title: string;
    width: number;
    detail?: Record<string, any>;
}
const dialog = reactive<Dialog>({
    title: '新建协议',
    width: 900,
    detail: undefined
});
const protocolTypeList = ref<
    Array<{
        id: string;
        protocolType: string;
        userDefined: boolean;
    }>
>([]);
const formData = reactive<any>({
    id: undefined,
    protocolNo: '',
    protocolName: '',
    protocolType: '',
    enableScript: false,
    scriptNo: '',
    checkType: '',
    checkName: '', // crc名称/哈希名称
    protocolDescription: '',
    crcType: '',
    crcInitValue: '',
    crcMultinomial: ''
});
const ruleFormRef = ref<FormInstance>();
const ruleForm = reactive<FormRules<any>>({
    protocolName: [{ required: true, message: '请输入协议名称', trigger: ['blur', 'change'] }],
    protocolNo: [
        { required: true, message: '请输入标识符', trigger: ['blur', 'change'] },
        {
            validator: (rule, value, callback) => {
                // 大写字母开头
                if (!/^[A-Z]/.test(value)) {
                    return callback(new Error('必须以大写字母开头'));
                }
                // 字母数字组合且符合驼峰命名
                if (!/^[A-Z][a-z0-9]+(?:[A-Z][a-z0-9]+)*$/.test(value)) {
                    return callback(new Error('必须是字母数字组合且符合驼峰命名法'));
                }
                callback();
            },
            trigger: ['blur', 'change']
        }
    ],
    protocolType: [{ required: true, message: '请选择协议类型', trigger: ['blur', 'change'] }],
    checkName: [
        {
            validator: (rule, value, callback) => {
                if (value) callback();
                else callback(new Error(`请选择${formData.checkType == 'crc' ? 'CRC名称' : '请选择哈希名称'}`));
            },
            trigger: ['blur', 'change']
        }
    ],
    scriptNo: [{ required: true, message: '请选择脚本', trigger: ['blur', 'change'] }],
    crcType: [{ required: true, message: '请选择CRC类型', trigger: ['blur', 'change'] }]
});
const crcMapList = ref<any>({});
const scriptMapList = ref<any>({});
const crcList = ref<any>([]);
// 是否为编辑
const isEdit = (par?: boolean): boolean => {
    if (par === undefined) {
        return dialog.title.includes('修改');
    } else {
        return dialog.title.includes('修改') && par;
    }
};
// 协议类型切换
const handleProtocolTypeChange = () => {
    if (formData.enableScript) {
        formData.scriptNo = '';
        getScriptList();
    }
};
// 是否启用脚本切换
const handleEnableScriptChange = () => {
    formData.scriptNo = '';
    if (formData.enableScript && formData.protocolType) getScriptList();
};
// 校验类型切换
const handleCheckTypeChange = () => {
    formData.crcType = '';
    formData.checkName = '';
    formData.crcInitValue = '';
    formData.crcMultinomial = '';
    if (!formData.checkType) {
        formData.checkType = '';
    } else if (formData.checkType === 'crc') {
        getCrcList();
    }
};
// crc 类型切换
const handleCrcTypeChange = () => {
    formData.checkName = '';
    formData.crcInitValue = '';
    formData.crcMultinomial = '';
    crcMapList.value[formData.crcType] = crcList.value.filter(item => item.crcType == formData.crcType);
};
// crc 名称切换
const handleCrcChange = () => {
    let targetData = crcMapList.value[formData.crcType].find(item => item.crcName === formData.checkName);
    if (targetData) {
        formData.crcInitValue = targetData.crcInitValue;
        formData.crcMultinomial = targetData.crcMultinomial;
    } else {
        formData.crcInitValue = '';
        formData.crcMultinomial = '';
    }
};
const buildForm = () => {
    let tergetData = JSON.parse(JSON.stringify(formData));
    delete tergetData.crcType;
    delete tergetData.crcInitValue;
    delete tergetData.crcMultinomial;
    return tergetData;
};
// 提交接口请求
const { run, loading } = useRequest(
    () => {
        return IoTProtocolService[isEdit() ? 'editProtocol' : 'createProtocol'](buildForm());
    },
    {
        manual: true,
        onSuccess(res) {
            if (isEdit()) {
                ElNotification({
                    title: '修改成功！',
                    type: 'success'
                });
            } else {
                ElMessageBox.confirm('请继续维护协议的内容！', '创建成功', {
                    confirmButtonText: '继续',
                    cancelButtonText: '完成',
                    type: 'success'
                })
                    .then(() => {
                        router.push({
                            name: 'IoT-protocol-detail',
                            params: {
                                id: res.data
                            }
                        });
                    })
                    .catch(() => {});
            }
            closeDialog();
        }
    }
);

// 获取脚本列表
const getScriptList = async () => {
    if (scriptMapList.value[formData.protocolType] && scriptMapList.value[formData.protocolType].length) return;
    const res = await runScriptService.getScriptList({
        scriptType: formData.protocolType + 'Script'
    });
    scriptMapList.value[formData.protocolType] = res.data;
};
// 获取协议类型列表
const getProtocolTypeList = async () => {
    const res = await IoTProtocolService.getProtocolTypeList();
    protocolTypeList.value = res.data;
};
// 表单提交
const submitForm = () => {
    ruleFormRef.value?.validate(valid => {
        valid && run();
    });
};
//关闭弹框
const closeDialog = () => {
    props.close();
    props.callBack?.();
};
// 获取CRC列表
const getCrcList = async (isInit?: boolean) => {
    if (crcList.value && crcList.value.length) return;
    const res: any = await IoTProtocolService.getCrcList();
    crcList.value = res.data;
    // 初始化反显赋值
    if (isInit) {
        let crcItem = res.data.find(item => item.crcName == formData.checkName);
        formData.crcType = crcItem.crcType;
        formData.crcInitValue = crcItem.crcInitValue;
        formData.crcMultinomial = crcItem.crcMultinomial;
        crcMapList.value[crcItem.crcType] = res.data.filter(item => item.crcType == formData.crcType);
    }
};
// 打开弹框
const openDialog = () => {
    if (props.row) {
        dialog.title = '修改协议';
        dialog.detail = JSON.parse(JSON.stringify(props.row));
        formData.id = props.row?.id;
        Object.keys(formData).forEach(key => {
            formData[key] = props.row?.[key];
        });
        if (props.row.checkType === 'crc') {
            getCrcList(true);
        }
        if (props.row.enableScript) {
            getScriptList();
        }
    } else {
        delete formData.id;
    }
};

const init = () => {
    getProtocolTypeList();
    openDialog();
};
init();
</script>
<style scoped lang="scss">
.create-edit-modal-wrapper {
    .el-form {
        display: flex;
        flex-wrap: wrap;
        .el-form-item {
            width: calc((100% - 10px) / 2);
        }
        .el-form-item:nth-child(even) {
            margin-left: 10px;
        }
        :deep(.protocol-box) {
            .el-form-item__content {
                display: flex;
                .el-select {
                    flex: 1;
                }
                .el-select + .el-select {
                    margin-left: 10px;
                }
            }
        }
    }
}
</style>
